package org.footito.android.data.database;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.TreeMap;

import org.footito.android.api.CommentFromAPI;
import org.footito.android.api.GroupsTeamFromAPI;
import org.footito.android.api.StatusFromAPI;
import org.footito.android.api.TeamFromAPI;
import org.footito.android.data.Comment;
import org.footito.android.data.Status;
import org.footito.android.data.Team;
import org.footito.android.data.TeamGroup;
import org.footito.android.data.sort.ComparatorTeamByName;
import org.footito.android.tools.ConvertingTools;
import org.footito.android.tools.GroupsComparator;
import org.footito.android.tools.Log;
import org.footito.android.tools.Settings;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;

public class FootitoDatabaseAdapter {
	private static FootitoDatabaseAdapter instance;

	public static FootitoDatabaseAdapter getInstance(Context context) {
		if (instance == null)
			instance = new FootitoDatabaseAdapter(context);
		return instance;
	}

	private FootitoDatabase db;
	private HashMap<Long, Team> cacheTeams;
	private TreeMap<Long, TeamGroup> cacheGroups;
	private Context context;

	private FootitoDatabaseAdapter(Context context) {
		db = new FootitoDatabase(context);
		db.open();
		this.context = context;
	}

	public void insertTeam(TeamFromAPI team) {
		ContentValues values = new ContentValues();
		values.put(FootitoDatabase.COL_TEAM_ID, team.getId());
		values.put(FootitoDatabase.COL_TEAM_LINK, team.getLink());
		values.put(FootitoDatabase.COL_TEAM_NAME, team.getName());
		values.put(FootitoDatabase.COL_TEAM_PICTURE, team.getPictureLink());
		values.put(FootitoDatabase.COL_TEAM_GROUPID, team.getGroup());

		db.insertTeam(values);

		cacheTeams = null;
	}

	public void insertGroupTeam(GroupsTeamFromAPI teamGroup) {
		ContentValues values = new ContentValues();
		values.put(FootitoDatabase.COL_TEAMGROUPS_ID, teamGroup.getId());
		values.put(FootitoDatabase.COL_TEAMGROUPS_NAME, teamGroup.getName());

		db.insertTeamGroup(values);

		cacheGroups = null;
	}

	public boolean insertStatus(StatusFromAPI status) {
		ContentValues values = new ContentValues();
		values.put(FootitoDatabase.COL_STATUS_ID, status.getId());
		values.put(FootitoDatabase.COL_STATUS_CONTENT, status.getContent());
		values.put(FootitoDatabase.COL_STATUS_IDTEAM, status.getTeamId());
		values.put(FootitoDatabase.COL_STATUS_LINK, status.getLink());
		long timestamp = ConvertingTools.getTimestampFromFormattedDate(status.getTimestamp());
		values.put(FootitoDatabase.COL_STATUS_TIMESTAMP, timestamp);
		values.put(FootitoDatabase.COL_STATUS_PLIKE, status.getPositiveLike());
		values.put(FootitoDatabase.COL_STATUS_NLIKE, status.getNegativeLike());

		return db.insertStatus(values) >= 0;
	}

	public boolean insertStatusAndComments(StatusFromAPI status) {
		ContentValues values = new ContentValues();
		values.put(FootitoDatabase.COL_STATUS_ID, status.getId());
		values.put(FootitoDatabase.COL_STATUS_CONTENT, status.getContent());
		values.put(FootitoDatabase.COL_STATUS_IDTEAM, status.getTeamId());
		values.put(FootitoDatabase.COL_STATUS_LINK, status.getLink());
		long timestamp = ConvertingTools.getTimestampFromFormattedDate(status.getTimestamp());
		values.put(FootitoDatabase.COL_STATUS_TIMESTAMP, timestamp);
		values.put(FootitoDatabase.COL_STATUS_PLIKE, status.getPositiveLike());
		values.put(FootitoDatabase.COL_STATUS_NLIKE, status.getNegativeLike());

		ArrayList<CommentFromAPI> comments = status.getComments();
		for (int i = 0; i < comments.size(); i++) {
			insertComment(comments.get(i));
		}

		return db.insertStatus(values) >= 0;
	}

	public void insertComment(CommentFromAPI comment) {
		ContentValues values = new ContentValues();
		values.put(FootitoDatabase.COL_COMMENT_ID, comment.getId());
		values.put(FootitoDatabase.COL_COMMENT_CONTENT, comment.getContent());
		values.put(FootitoDatabase.COL_COMMENT_IDTEAM, comment.getIdTeam());
		values.put(FootitoDatabase.COL_COMMENT_IDSTATUS, comment.getIdStatus());
		values.put(FootitoDatabase.COL_COMMENT_PLIKE, comment.getPositive_likes());
		values.put(FootitoDatabase.COL_COMMENT_NLIKE, comment.getNegative_likes());

		db.insertComment(values);
	}

	public void loadCommentsForStatus(Status status) {

		String selection = FootitoDatabase.REQUEST_COMS_BY_STATUS;
		String[] selectionArgs = { Long.toString(status.getId()) };
		Cursor c = db.getAllCommentsCursor(null, selection, selectionArgs, null);

		if (c.moveToFirst()) {
			do {
				Team team = getTeam(c.getInt(FootitoDatabase.COLNUM_COMMENT_IDTEAM));
				long id = c.getLong(FootitoDatabase.COLNUM_COMMENT_ID);
				String content = c.getString(FootitoDatabase.COLNUM_COMMENT_CONTENT);
				long positiveLike = c.getLong(FootitoDatabase.COLNUM_COMMENT_PLIKE);
				long negativeLike = c.getLong(FootitoDatabase.COLNUM_COMMENT_NLIKE);
				Comment comment = new Comment(id, content, team, status, positiveLike, negativeLike);
				status.addComment(comment);
			} while (c.moveToNext());
		}

		c.close();
	}

	public Team getTeam(long teamID) {
		return getTeams().get(new Long(teamID));
	}

	private HashMap<Long, Team> getTeams() {
		if (cacheTeams == null) {
			cacheTeams = loadTeams();
		}
		return cacheTeams;
	}

	private HashMap<Long, Team> loadTeams() {
		HashMap<Long, Team> result = new HashMap<Long, Team>();
		Cursor c = db.getAllTeamsCursor(null, null, null, null);

		if (c.moveToFirst()) {
			do {
				String name = c.getString(FootitoDatabase.COLNUM_TEAM_NAME);
				String pictureLink = c.getString(FootitoDatabase.COLNUM_TEAM_PICTURE);
				String link = c.getString(FootitoDatabase.COLNUM_TEAM_LINK);
				long id = c.getLong(FootitoDatabase.COLNUM_TEAM_ID);
				TeamGroup group = getTeamGroup(c.getInt(FootitoDatabase.COLNUM_TEAM_GROUPID));
				Team team = new Team(name, pictureLink, link, id, group);
				result.put(new Long(team.getId()), team);

			} while (c.moveToNext());
		}
		return result;
	}

	private TeamGroup getTeamGroup(long groupID) {
		return getTeamGroups().get(new Long(groupID));
	}

	private TreeMap<Long, TeamGroup> getTeamGroups() {
		if (cacheGroups == null) {
			cacheGroups = loadTeamGroups();
		}
		return cacheGroups;
	}

	private TreeMap<Long, TeamGroup> loadTeamGroups() {
		TreeMap<Long, TeamGroup> result = new TreeMap<Long, TeamGroup>();
		Cursor c = db.getAllTeamGroupsCursor(null, null, null, null);

		if (c.moveToFirst()) {
			do {
				long id = c.getLong(FootitoDatabase.COLNUM_TEAMGROUPS_ID);
				String name = c.getString(FootitoDatabase.COLNUM_TEAMGROUPS_NAME);
				TeamGroup teamgroup = new TeamGroup(id, name);
				result.put(new Long(teamgroup.getId()), teamgroup);

			} while (c.moveToNext());
		}
		return result;
	}

	public void insertComments(ArrayList<CommentFromAPI> comments) {
		for (int i = 0; i < comments.size(); i++) {
			insertComment(comments.get(i));
		}
	}

	public void insertGroupsTeam(ArrayList<GroupsTeamFromAPI> groups) {
		for (int i = 0; i < groups.size(); i++) {
			insertGroupTeam(groups.get(i));
		}
	}

	public int insertStatus(ArrayList<StatusFromAPI> status) {
		int res = 0;
		for (int i = 0; i < status.size(); i++) {
			if (insertStatus(status.get(i)))
				res++;
		}
		return res;
	}

	public int insertStatusAndComments(ArrayList<StatusFromAPI> status) {
		int res = 0;
		for (int i = 0; i < status.size(); i++) {
			if (insertStatusAndComments(status.get(i)))
				res++;
		}
		return res;
	}

	public void insertTeams(ArrayList<TeamFromAPI> teams) {
		for (int i = 0; i < teams.size(); i++) {
			insertTeam(teams.get(i));
		}
	}

	public ArrayList<Status> getStatusByPage(long baseTimestamp, int page, int limit) {
		ArrayList<Status> result = new ArrayList<Status>();
		page = page + 1;
		if (Settings.getInitialized(context)) {
			String selection = FootitoDatabase.REQUEST_STATUS_BY_TIMESTAMP;
			String[] selectionArgs = new String[] { Long.toString(baseTimestamp) };
			Cursor c = db.getStatusByPageCursor(null, selection, selectionArgs, null,
					Integer.toString(limit), Integer.toString(page * limit));
			// Cursor c = db.getStatusByPageCursor(null, null, null, null,
			// Integer.toString(limit),
			// Integer.toString(page * limit));

			if (c.moveToFirst()) {
				do {
					Status status = getStatusFromCursor(c);
					result.add(status);
				} while (c.moveToNext());
			}

			// if (result.size() == 0) {
			// result = UpdateTools.performLoadMoreStatus(context, 50,
			// getStatusCount());
			// }
		}
		return result;
	}

	public ArrayList<Status> getStatusByInsertion(long baseTimestamp, boolean isBefore) {
		ArrayList<Status> result = new ArrayList<Status>();
		if (Settings.getInitialized(context)) {
			String selection;
			if (isBefore)
				selection = FootitoDatabase.REQUEST_STATUS_BY_INSERTION_BEFORE;
			else
				selection = FootitoDatabase.REQUEST_STATUS_BY_INSERTION_AFTER;
			String[] selectionArgs = new String[] { Long.toString(baseTimestamp) };
			Cursor c = db.getAllStatusCursor(null, selection, selectionArgs, null);

			if (c.moveToFirst()) {
				do {
					Status status = getStatusFromCursor(c);
					result.add(status);

				} while (c.moveToNext());
			}
		}
		return result;
	}

	private int getStatusCount() {
		String[] projection = new String[] { "count()" };
		Cursor c = db.getAllStatusCursor(projection, null, null, null);
		int res = 0;
		if (c.moveToFirst()) {
			res = c.getInt(0);
		}
		return res;
	}

	private Status getStatusFromCursor(Cursor c) {
		long id = c.getLong(FootitoDatabase.COLNUM_STATUS_ID);
		Team team = getTeam(c.getInt(FootitoDatabase.COLNUM_STATUS_IDTEAM));
		long timestamp = c.getLong(FootitoDatabase.COLNUM_STATUS_TIMESTAMP);
		String content = c.getString(FootitoDatabase.COLNUM_STATUS_CONTENT);
		String link = c.getString(FootitoDatabase.COLNUM_STATUS_LINK);
		GregorianCalendar insertiontime = new GregorianCalendar();
		insertiontime.setTimeInMillis(c.getLong(FootitoDatabase.COLNUM_STATUS_INSERTION));
		long positiveLike = c.getLong(FootitoDatabase.COLNUM_STATUS_PLIKE);
		long negativeLike = c.getLong(FootitoDatabase.COLNUM_STATUS_NLIKE);
		Status status = new Status(id, team, timestamp, content, link, insertiontime, positiveLike,
				negativeLike);
		loadCommentsForStatus(status);
		return status;
	}

	public Status getStatus(long statusId) {
		Cursor c = db.getStatusCursor(statusId);
		if (c.moveToNext())
			return getStatusFromCursor(c);
		else
			return null;
	}

	public Status getFirstStatus() {
		Cursor c = db.getFirstStatusCursor();
		if (c.moveToNext())
			return getStatusFromCursor(c);
		else
			return null;
	}
	
	public Status getLastStatus() {
		Cursor c = db.getLastStatusCursor();
		if (c.moveToNext())
			return getStatusFromCursor(c);
		else
			return null;
	}
	
	//FONCTION INTERNE
	public ArrayList<Status> getModererStatus() {
		ArrayList<Status> result = new ArrayList<Status>();
		
		if (Settings.getInitialized(context)) {
			Cursor cursor = db.getStatusModererCursor();

		    cursor.moveToFirst();
		    while(!cursor.isAfterLast()) {

		        result.add(getStatusFromCursor(cursor));

		        cursor.moveToNext();
		    }
		}
		return result;
	}

	public Team[] getAllTeams() {
		Team[] array = (Team[]) cacheTeams.values().toArray(new Team[cacheTeams.values().size()]);
		return array;
	}

	public TeamGroup[] getAllGroupsTeam() {
		TeamGroup[] array = (TeamGroup[]) getTeamGroups().values().toArray(
				new TeamGroup[cacheGroups.values().size()]);
		Arrays.sort(array, new GroupsComparator());
		return array;
	}

	public TreeMap<TeamGroup, ArrayList<Team>> getAllTeamsByGroup() {
		Team[] teams = getAllTeams();
		TeamGroup[] groups = getAllGroupsTeam();
		TreeMap<TeamGroup, ArrayList<Team>> result = new TreeMap<TeamGroup, ArrayList<Team>>();
		for (int i = 0; i < groups.length; i++) {
			result.put(groups[i], new ArrayList<Team>());
		}

		for (int i = 0; i < teams.length; i++) {
			result.get(teams[i].getGroup()).add(teams[i]);
		}

		for (int i = 0; i < groups.length; i++) {
			Collections.sort(result.get(groups[i]), new ComparatorTeamByName());
		}
		return result;
	}

}
